<?php
/**
 * HTTP响应
 * @author Leo 2010-09-07
 */

class Response {
	private $action;
	private $app;
	private $action_name;
	private $tpl_data = array ();
	private $duration = 0;
	private $tpl;
	private $layout;
	private $compress = false;
	private $_compress;
	private $cache_key = '';
	private $cache_content = '';
	private $compress_method = '';
	public $view = 'htmlView';
	public $title = '';
	public $keywords = '';
	public $desc = '';
	/**
	 * 构造函数
	 * @param Action $action
	 * @param string $app 应用名称
	 */
	public function __construct($action, $app) {
		if ($action != null) {
			$this->setAction ( $action );
		}
		$this->_compress = ! ini_get ( 'zlib.output_compression' ) && 'ob_gzhandler' != ini_get ( 'output_handler' ) && isset ( $_SERVER ['HTTP_ACCEPT_ENCODING'] );
		$this->app = $app;
		$this->compress ( true );
	}
	/**
	 * 设置当前Action
	 * @param Action $action
	 */
	public function setAction($action) {
		$this->action = $action;
		$this->action_name = get_class ( $action );
	}
	/**
	 * 禁用浏览器缓存
	 */
	public function nocache() {
		$headers = array ('Expires' => 'Wed, 11 Jan 1984 05:00:00 GMT', 'Last-Modified' => gmdate ( 'D, d M Y H:i:s' ) . ' GMT', 'Cache-Control' => 'no-cache, must-revalidate, max-age=0', 'Pragma' => 'no-cache' );
		foreach ( $headers as $header => $val ) {
			@header ( $header . ': ' . $val );
		}
	}
	/**
	 * 设置是否压缩输出
	 * @param boolean $enable true 启用压缩,false 禁用压缩
	 */
	public function compress($enable) {
		$this->compress = $enable && $this->_compress;
		if ($this->compress) {
			if (false !== strpos ( strtolower ( $_SERVER ['HTTP_ACCEPT_ENCODING'] ), 'deflate' ) && function_exists ( 'gzdeflate' )) {
				$this->compress_method = 'deflate';
			} else if (false !== strpos ( strtolower ( $_SERVER ['HTTP_ACCEPT_ENCODING'] ), 'gzip' ) && function_exists ( 'gzencode' )) {
				$this->compress_method = 'gzip';
			} else {
				$this->compress_method = 'none';
			}
		} else {
			$this->compress_method = 'none';
		}
	}
	/**
	 * 开始输出内容
	 */
	public function begin() {
		@ob_flush (); //输出缓冲区中的内容
		@ob_clean ();
		$this->compress ( false );
	}
	/**
	 * 立即输出(不压缩)内容,会将之前设置的header同时输出.
	 * 同时该方法也会关闭压缩输出
	 * @param string $msg 要输出的内容
	 */
	public function write($msg) {
		echo $msg;
		flush ();
	}
	/**
	 * 立即输出(不压缩)内容,会将之前设置的header同时输出.
	 * 同时该方法也会关闭压缩输出
	 * @param string $msg 要输出的内容
	 */
	public function out($msg) {
		echo $msg;
		flush ();
	}
	/**
	 * 跳转
	 * @param string $location 要转到的网址
	 * @param array $args 参数
	 * @param int $status 响应代码
	 *
	 */
	public function redirect($location, $args = "", $status = 302) {
		if (! $location) {
			return false;
		}
		if (! empty ( $args ) && is_string ( $args )) {
			if (strpos ( $location, '?' ) !== false) {
				$location .= '&' . $args;
			} else {
				$location .= '?' . $args;
			}
		}
		if ($is_IIS) {
			@header ( "Refresh: 0;url=$location" );
		} else {
			if (php_sapi_name () != 'cgi-fcgi') {
				status_header ( $status ); // This causes problems on IIS and some FastCGI setups
			}
			@header ( "Location: $location", true, $status );
		}
		$this->close ( true );
	}
	/**
	 * 设置变量,将内容添加到视图.如果视图有模板,则在模板中可以直接使用.
	 * @param string $name 变量名
	 * @param mixed $value 变量值
	 */
	public function assign($name, $value = '') {
		if (is_array ( $name )) {
			$this->tpl_data = array_merge ( $this->tpl_data, $name );
		} else if (is_string ( $name )) {
			$this->tpl_data [$name] = $value;
		}
	}
	/**
	 * 设置视图
	 * @param string $view 视图
	 * @param string $tpl 模板,为空时使用默认模板
	 */
	public function setView($view, $tpl = '') {
		$this->view = $view;
		if (! empty ( $tpl )) {
			$this->tpl = $tpl;
		}
	}
	/**
	 * 设置模板
	 * @param string $tpl 模板文件,相对于views目录
	 */
	public function setTemplate($tpl) {
		$this->tpl = $tpl;
	}
	/**
	 * 设置布局,只有在视图为LayoutView时有用.
	 * 
	 * @param string $layout
	 */
	public function setLayout($layout) {
		$this->layout = $layout;
	}
	/**
	 * 获取当前布局
	 * 
	 */
	public function getLayout() {
		return $this->layout;
	}
	/**
	 * 设置缓存时间与缓存KEY
	 * @param string $cache_key 缓存KEY
	 * @param int $duration
	 */
	public function cache($cache_key, $duration = 900) {
		$this->duration = $duration;
		$this->cache_key = $cache_key;
	}
	/**
	 * 预检测缓存
	 * @param string $cache_key
	 * @return boolean 缓存命中返回true,反之返回false
	 */
	public function preGetCache($cache_key) {
		
		$content = cache_get ( $cache_key . '-' . $this->compress_method );
		if (! empty ( $content )) {
			$this->cache_content = $content;
			return true;
		}
		return false;
	}
	/**
	 * 输出头信息
	 * @param int $code
	 */
	public function setStatus($code = null) {
		status_header ( $code );
	}
	/**
	 * 绘制
	 * @param mixed $cached false为缓存未命中,string为缓存KEY
	 */
	public function render($cached = false) {
		$ioc = get_current_ioc ();
		$view = $ioc->get ( $this->view );
		if (is_null ( $view )) {
			trigger_error ( 'The view named ' . $this->view . ' is not found in IOC', E_USER_ERROR );
		} else {
			$view->setHeader ();
		}
		fire ( 'before_render', $this );
		if ($cached === false) { //不缓存
			$tpl = empty ( $this->tpl ) ? $this->action_name : $this->tpl;
			$tpl = APPS . $this->app . DS . 'views' . DS . $tpl;
			$this->assign ( 'PAGE_TITLE', $this->title );
			$this->assign ( 'PAGE_KEYWORDS', $this->keywords );
			$this->assign ( 'PAGE_DESC', $this->desc );
			$content = $view->render ( $this->tpl_data, $this, $tpl ) or false;
		} else { //缓存命中
			$content = $this->cache_content;
		}
		fire ( 'after_render', $this, $content );
		$content = apply_filter ( 'after_render_content', $content );
		if (false !== $content) {
			$error = @ob_get_contents ();
			@ob_end_clean ();
			@ob_start ();
			if ($this->compress_method !== 'none') {
				@header ( 'Vary: Accept-Encoding' );
				@header ( 'Content-Encoding: ' . $this->compress_method );
			}
			fire ( 'before_output', $this, $content );
			$out = $content;
			if ($cached === false) { //缓存未命中时
				if (! empty ( $error )) {
					$out = $error . $out;
				}
				if ($this->compress_method == 'gzip') {
					$out = gzencode ( $content, 3 );
				} else if ($this->compress_method == 'deflate') {
					$out = gzdeflate ( $content, 3 );
				}
				if (! empty ( $this->cache_key ) && $this->duration > 0) {
					cache_add ( $this->cache_key . '-' . $this->compress_method, $content, $this->duration );
				}
			}
			echo $out;
			fire ( 'after_output', $this, $content );
		} else {
			fire ( 'the_content_empty', $this );
		}
	}
	/**
	 * 输出错误信息,如果当前在调试模式下,输出信息,反之设置头响应信息.
	 * @param string $msg 要输出的错误信息
	 * @param int $status 头响应信息状态
	 */
	public function error($msg, $status = null) {
		if (defined ( 'DEBUG' ) && DEBUG) {
			trigger_error ( '[' . WEBSITE . '] ' . $msg, E_USER_ERROR );
		} else {
			if (! is_null ( $status )) {
				$this->setStatus ( $status );
			}
		}
	}
	/**
	 * 关闭响应输出
	 */
	public function close($exit = false) {
		@ob_end_flush (); //关闭由nutzp.inc开启的缓冲区
		if ($exit === true) {
			exit ();
		}
	}
}